package identical_scheduling_algorithm;

import ilog.concert.IloException;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

import de.cau.apo.problems.identicalscheduling.ISInstance;


/**
 * Löst das Schedulingproblem auf identischen Maschinen. Grundlage für den Algorithmus ist der Alogrithm 1 aus dem 
 * Paper "Scheduling jobs on uniform processors revisited" von Klaus Jansen und Christina Robenek.
 * Fügt die einzelnen Klassen des Paket zu einem Programm zusammen
 * 
 * @author Oliver Hense
 * @author Tim Dopke
 *
 */
public class Algorithm1 {
	
	/* 
	 * 
	 * Die Main Methode der Klasse Algorithmus1 starten um das Programm auszufürhren.
	 * 
	 * 
	 */

	double delta = 0.175;
    double maxGap = 2;
	
	double makeSpan;
	double minT;
	double maxT;
	ISInstance instanz;

	public Algorithm1() {
		instanz = new ISInstance();
		try {
			if (instanz.parseInstance("INSTANCES/U_2_0100_25_8.txt")) {
				ListScheduling ls = new ListScheduling(instanz.numberMachines,
						instanz.jobs);
				maxT = ls.solve()*(1+delta);
				minT = maxT / 2.0;
				makeSpan = (maxT + minT) / 2.0;
				System.out.println("anfang");
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}		
	}

	public static void main(String[] args) {
		Algorithm1 algo = new Algorithm1();
	  //algo.eingabe();
		algo.solve();

	}

	public void solve() {
		try {

			// Round Jobs
			RoundJobs rj = new RoundJobs();
			double[] roundedJobs = rj.roundJobs(delta, makeSpan, instanz.jobs);
			if (roundedJobs != null) {

				// Solve LP
				LpSolver solver = new LpSolver(delta, makeSpan, instanz.jobs);

				Cofiguration conf = solver.lpSolver();

				// Cross Off Values
				CrossOff cutter = new CrossOff(maxGap, conf,
						instanz.getNumberMachines(), roundedJobs, delta);
				cutter.crossOffValues();

				// Dynamic Program
				DynamicProgram dynamicSolver = new DynamicProgram(
						cutter.getNewRoundedJobs(), makeSpan, delta);

				// initialize
				dynamicSolver.initialize();
				dynamicSolver.printConfig();
				// solve
				dynamicSolver.solveDynamicProgram();

				int minBin = dynamicSolver.getSolution();
				minBin = minBin + cutter.getCrossOfJobs();
				System.out.println("Es werden insgesamt " + minBin
						+ " Bins benötigt.");

				// T too small?
				if (minBin > instanz.numberMachines) {
					System.out.println("minT = " + minT + " maxT = " + maxT
							+ " makespan = " + makeSpan);
					minT = makeSpan;
					makeSpan = (minT + maxT) / 2.0;
					this.solve();
				}

				// T too big?
				else {
					ArrayList<Double> cuttedMachines = cutter
							.getOccupancy();
					ArrayList<Double> dynamicMachines = dynamicSolver
							.getOccupancy();
 
					double[] machines = new double[instanz.getNumberMachines()];
				    for (int i = 0; i < cuttedMachines.size(); i++)
						machines[i] = cuttedMachines.get(i);
				    for (int i = 0; i < dynamicMachines.size(); i++)
						machines[i + cuttedMachines.size()] = dynamicMachines.get(i);
				    
				    // Schedul small jobs
				    ListSchedulingForSmallJobs ls2 = new ListSchedulingForSmallJobs(instanz.getNumberMachines(), rj.getSmallJobs(),machines);
				    System.out.println();
				    System.out.println("Belegung der Maschinen ohne die kleinen Jobs:");
				    for (int i = 0; i < machines.length; i++)
						System.out.print(machines[i] + ",");
					System.out.println();System.out.println();
				    System.out.println("Belegung der Maschinen inklusive der kleinen Jobs:");
					machines = ls2.solve();
					
					// T zu klein gewählt? (kleine Jobs können nicht gepackt werden)
					if (ls2.getMax() > (1 + delta)) {
						System.out.println("minT = " + minT + " maxT = "+ maxT + " makespan = " + makeSpan);
						minT = makeSpan;
						makeSpan = (minT + maxT) / 2.0;
						this.solve();
						
					} else {
						
					// MakeSpan big enough?
					if ((1 + delta) * minT >= maxT) {
												
						for (int i = 0; i < machines.length; i++)
							System.out.print(machines[i] + ",");
						System.out.println();

						System.out.println();
							System.out.println("Fertig mit makeSpan "
									+ makeSpan);
						}
					
					// Reduce MakeSpan
					else {
						System.out.println("minT = " + minT + " maxT = " + maxT
								+ " makespan = " + makeSpan);
						maxT = makeSpan;
						makeSpan = (minT + maxT) / 2.0;
						this.solve();
					}
				}
				}
			} else {
				System.out.println("Es gibt keine gerundeten Jobs!");
			}

		} catch (IloException exc) {
			System.out
					.println("Gehe zurück zum Anfang, makeSpan ist zu klein für LP");
			minT = makeSpan;
			makeSpan = (minT + maxT) / 2.0;
			this.solve();
		}
	}
	
	public void eingabe(){
		
		Scanner scan = new Scanner(System.in);
		System.out.println("MaxGap?");
		maxGap = scan.nextDouble(); 
		System.out.println("Delta?");
		delta = scan.nextDouble();
		
		scan.close();
		
		
		
	}
}